import { _decorator, Component, AudioClip, AudioSource, tween, Tween } from 'cc';
import { AudioConfig } from '../config/AudioConfig';

const { ccclass, property } = _decorator;

/**
 * 音频系统
 * 
 * 功能：
 * 1. 管理游戏音频播放
 * 2. 处理音频资源加载
 * 3. 控制音频混音和切换
 * 4. 管理音频状态
 * 
 * 特点：
 * 1. 音频池管理
 * 2. 淡入淡出支持
 * 3. 优先级系统
 * 4. 3D音频支持
 */
@ccclass('AudioSystem')
export class AudioSystem extends Component {
    @property([AudioClip])
    private musicClips: AudioClip[] = [];

    @property([AudioClip])
    private effectClips: AudioClip[] = [];

    @property(AudioSource)
    private musicSource: AudioSource | null = null;

    @property(AudioSource)
    private effectSource: AudioSource | null = null;

    @property
    private defaultFadeDuration: number = 1.0;

    private static _instance: AudioSystem | null = null;
    private audioMap: Map<string, AudioClip> = new Map();
    private currentMusic: string = '';
    private currentMusicVolume: number = AudioConfig.DEFAULT_VOLUME.MUSIC;
    private currentEffectVolume: number = AudioConfig.DEFAULT_VOLUME.EFFECT;
    private musicFadeTween: Tween<any> | null = null;

    public static get instance(): AudioSystem {
        return this._instance!;
    }

    onLoad() {
        if (AudioSystem._instance === null) {
            AudioSystem._instance = this;
            this.initAudioSystem();
        } else {
            this.node.destroy();
        }
    }

    private initAudioSystem() {
        // 初始化音频映射
        this.musicClips.forEach(clip => {
            this.audioMap.set(clip.name, clip);
        });
        this.effectClips.forEach(clip => {
            this.audioMap.set(clip.name, clip);
        });

        // 设置默认音量
        this.setMusicVolume(this.currentMusicVolume);
        this.setEffectVolume(this.currentEffectVolume);
    }

    public async playMusic(name: string, loop: boolean = true, fadeIn: boolean = true) {
        if (this.currentMusic === name) return;

        const clip = this.audioMap.get(name);
        if (!clip || !this.musicSource) return;

        // 如果有正在播放的音乐，先淡出
        if (this.currentMusic && fadeIn) {
            await this.fadeOutMusic();
        } else {
            this.stopMusic();
        }

        // 设置新的音乐
        this.musicSource.clip = clip;
        this.musicSource.loop = loop;
        this.musicSource.volume = fadeIn ? 0 : this.currentMusicVolume;
        this.musicSource.play();
        this.currentMusic = name;

        // 淡入新音乐
        if (fadeIn) {
            await this.fadeInMusic();
        }
    }

    public async fadeOutMusic(): Promise<void> {
        if (!this.musicSource || this.musicSource.volume <= 0) return Promise.resolve();

        // 停止当前的淡入淡出效果
        if (this.musicFadeTween) {
            this.musicFadeTween.stop();
        }

        return new Promise<void>((resolve) => {
            const startVolume = this.musicSource!.volume;
            this.musicFadeTween = tween(this.musicSource)
                .to(this.defaultFadeDuration, { volume: 0 })
                .call(() => {
                    this.musicSource!.stop();
                    this.musicSource!.volume = startVolume;
                    resolve();
                })
                .start();
        });
    }

    private async fadeInMusic(): Promise<void> {
        if (!this.musicSource) return Promise.resolve();

        // 停止当前的淡入淡出效果
        if (this.musicFadeTween) {
            this.musicFadeTween.stop();
        }

        return new Promise<void>((resolve) => {
            this.musicFadeTween = tween(this.musicSource)
                .to(this.defaultFadeDuration, { volume: this.currentMusicVolume })
                .call(() => resolve())
                .start();
        });
    }

    public async crossFadeMusic(name: string, duration: number = this.defaultFadeDuration) {
        const clip = this.audioMap.get(name);
        if (!clip || !this.musicSource || this.currentMusic === name) return;

        // 创建临时音源用于交叉淡变
        const tempNode = new Node('TempAudio');
        const tempSource = tempNode.addComponent(AudioSource);
        tempSource.clip = clip;
        tempSource.volume = 0;
        this.node.addChild(tempNode);

        // 开始播放新音乐
        tempSource.play();

        // 同时淡出当前音乐和淡入新音乐
        await Promise.all([
            new Promise<void>((resolve) => {
                tween(this.musicSource)
                    .to(duration, { volume: 0 })
                    .call(() => {
                        this.musicSource!.stop();
                        resolve();
                    })
                    .start();
            }),
            new Promise<void>((resolve) => {
                tween(tempSource)
                    .to(duration, { volume: this.currentMusicVolume })
                    .call(() => resolve())
                    .start();
            })
        ]);

        // 更新音源引用
        this.musicSource.clip = clip;
        this.musicSource.volume = this.currentMusicVolume;
        this.musicSource.play();
        this.currentMusic = name;

        // 清理临时节点
        tempNode.destroy();
    }

    public playEffect(name: string, volumeScale: number = 1) {
        const clip = this.audioMap.get(name);
        if (clip && this.effectSource) {
            this.effectSource.playOneShot(clip, volumeScale * this.currentEffectVolume);
        }
    }

    public setMusicVolume(volume: number, fade: boolean = true) {
        this.currentMusicVolume = Math.max(0, Math.min(1, volume));
        
        if (this.musicSource) {
            if (fade) {
                tween(this.musicSource)
                    .to(this.defaultFadeDuration, { volume: this.currentMusicVolume })
                    .start();
            } else {
                this.musicSource.volume = this.currentMusicVolume;
            }
        }
    }

    public setEffectVolume(volume: number) {
        this.currentEffectVolume = Math.max(0, Math.min(1, volume));
        if (this.effectSource) {
            this.effectSource.volume = this.currentEffectVolume;
        }
    }

    onDestroy() {
        if (this.musicFadeTween) {
            this.musicFadeTween.stop();
        }
    }
} 